package com.qo.qsdk.http;

import android.app.Activity;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.google.gson.Gson;
import com.qo.qsdk.config.QSDKLanguage;
import com.qo.qsdk.model.InitModel;
import com.qo.qsdk.model.SDKInfoModel;
import com.qo.qsdk.param.GameRoleParams;
import com.qo.qsdk.ui.IBaseActivity;
import com.qo.qsdk.utils.Language;
import com.qo.qsdk.utils.QSDKHelper;

import java.io.IOException;
import java.util.HashMap;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import okhttp3.CacheControl;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class QSDKHttp {

    private static final String TAG = QSDKHttp.class.getSimpleName();
    private volatile static QSDKHttp INSTANCE;
    private Handler mHandler;

    private static String BASE_URL = "http://api.unicornfuns.com";
    public static String BASE_VERSION = "/v1";

    private Call mHisList;
    public void getHisList(Activity activity, QResultCallback resultCallback) {
        if (mHisList != null) mHisList.cancel();
        HashMap<String, Object> p = new HashMap<String, Object>();
        mHisList = req(activity, true, "/member/history_accounts", p, resultCallback);
    }

    private Call mLoginAccount;
    public void loginAccount(Activity activity, String account, String pwd, QResultCallback resultCallback) {
        if (mLoginAccount != null) mLoginAccount.cancel();
        HashMap<String, Object> p = new HashMap<String, Object>();
        p.put("account", account);
        p.put("password", pwd);
        mLoginAccount = req(activity, true, "/member/signin", p, resultCallback);
    }

    private Call mRegisterAccount;
    public void registerAccount(Activity activity, String account, String pwd, QResultCallback resultCallback) {
        if (mRegisterAccount != null) mRegisterAccount.cancel();
        HashMap<String, Object> p = new HashMap<String, Object>();
        p.put("account", account);
        p.put("password", pwd);
        mRegisterAccount = req(activity, true, "/member/signup", p, resultCallback);
    }

    private Call mBindAccount;
    public void bindAccount(Activity activity, String account, String pwd, String token, QResultCallback resultCallback) {
        if (mBindAccount != null) mBindAccount.cancel();
        HashMap<String, Object> p = new HashMap<String, Object>();
        p.put("account", account);
        p.put("password", pwd);
        p.put("token", token);
        mBindAccount = req(activity, true, "/member/bind/member", p, resultCallback);
    }

    private Call mLoginGuest;
    public void loginGuest(Activity activity, QResultCallback resultCallback) {
        if (mLoginGuest != null) mLoginGuest.cancel();
        HashMap<String, Object> p = new HashMap<String, Object>();
        mLoginGuest = req(activity, true, "/member/tourist", p, resultCallback);
    }

    private Call mLoginToken;
    public void loginToken(Activity activity, String token, QResultCallback resultCallback) {
        if (mLoginToken != null) mLoginToken.cancel();
        HashMap<String, Object> p = new HashMap<String, Object>();
        p.put("token", token);
        mLoginToken = req(activity, true, "/member/verify", p, resultCallback);
    }

    public void paymentGenOrder(Activity activity, String token, String productId, String tradeSn, String extra, String serverId, String roleId, String roleName, QResultCallback resultCallback) {
        HashMap<String, Object> p = new HashMap<String, Object>();
        p.put("token", token);
        p.put("product_id", productId);
        p.put("trade_sn", tradeSn);
        p.put("extra", extra);
        p.put("server_id", serverId);
        p.put("role_id", roleId);
        p.put("role_name", roleName);
        req(activity, true, "/payment/order", p, resultCallback);
    }

    public void submitRole(Activity activity, String token, GameRoleParams params, QResultCallback resultCallback) {
        try {
            HashMap<String, Object> p = new HashMap<String, Object>();
            p.put("token", token);
            p.put("server_id", params.getServerId());
            p.put("server_name", params.getServerName());
            p.put("role_id", params.getRoleId());
            p.put("role_name", params.getRoleName());

            p.put("gender", params.getRoleGender());
            p.put("power", Integer.parseInt(params.getPower()));
            p.put("level", Integer.parseInt(params.getRoleLevel()));
            p.put("event_time", params.getRoleLevelUpTime());
            req(activity, true, "/report/role", p, resultCallback);
        }catch (Exception e) {
            e.printStackTrace();
            if (resultCallback != null) resultCallback.onError(1000, "23");
        }
    }

    public void verifyPay(Activity activity, String purchaseToken,String tradeSn, QResultCallback resultCallback) {
        HashMap<String, Object> p = new HashMap<String, Object>();
        p.put("receipt", purchaseToken);
        p.put("order_sn", tradeSn);
        req(activity, true, "/payment/google", p, resultCallback);
    }

    public void loginGoogle(Activity activity, String googleToken, String account, QResultCallback resultCallback) {
        bindGoogle(activity, googleToken, account, "", resultCallback);
    }

    private Call mBindGoogle;
    public void bindGoogle(Activity activity, String googleToken, String account, String bindingToken, QResultCallback resultCallback) {
        if (mBindGoogle != null) mBindGoogle.cancel();
        boolean isBind = bindingToken != null && bindingToken.length() > 0;
        HashMap<String, Object> p = new HashMap<String, Object>();
        p.put("id_token", googleToken);
        if (isBind) p.put("token", bindingToken);
        mBindGoogle = req(activity, true, isBind ? "/member/bind/google" : "/member/google", p, resultCallback);
    }

    public void loginApple(Activity activity, String appleToken, String bindingToken,  QResultCallback resultCallback) {
        bindApple(activity, appleToken, "", resultCallback);
    }

    private Call mBindApple;
    public void bindApple(Activity activity, String appleToken, String bindingToken,  QResultCallback resultCallback) {
        if (mBindApple != null) mBindApple.cancel();
        boolean isBind = bindingToken != null && bindingToken.length() > 0;
        HashMap<String, Object> params = new HashMap<>();
        params.put("id_token", appleToken);
        if (isBind) params.put("token", bindingToken);
        mBindApple = req(activity, true, isBind ? "/member/bind/apple" : "/member/apple", params, resultCallback);
    }

    public void loginFacebook(Activity activity, String fbToken,  QResultCallback resultCallback) {
        bindFacebook(activity, fbToken, "", resultCallback);
    }

    private Call mBindFb;
    public void bindFacebook(Activity activity, String fbToken, String bindingToken,  QResultCallback resultCallback) {
        if (mBindFb != null) mBindFb.cancel();
        boolean isBind = bindingToken != null && bindingToken.length() > 0;
        HashMap<String, Object> params = new HashMap<>();
        params.put("id_token", fbToken);
        if (isBind) params.put("token", bindingToken);
        mBindFb = req(activity, true, isBind ? "/member/bind/facebook" : "/member/facebook", params, resultCallback);
    }

    private Call mFirebaseToken;
    public void firebaseToken(Activity activity, String firebaseToken, String token,  QResultCallback resultCallback) {
        if (mFirebaseToken != null) mFirebaseToken.cancel();
        HashMap<String, Object> params = new HashMap<>();
        params.put("firebaseToken", firebaseToken);
        params.put("token", token);
        mFirebaseToken = req(activity, true, "/push/bind/firebase", params, resultCallback);
    }

    private Call mInit;
    public void init(Activity activity, QResultCallback resultCallback) {
        if (mInit != null) mInit.cancel();
        HashMap<String, Object> p = new HashMap<String, Object>();
        mInit = req(activity, false, "/initialize", p, resultCallback);
    }

    public QSDKHttp() {
        mHandler = new Handler(Looper.getMainLooper());
    }

    public static QSDKHttp getInstance() {
        if (INSTANCE == null) {
            synchronized (QSDKHttp.class) {
                if (INSTANCE == null) {
                    INSTANCE = new QSDKHttp();
                }
            }
        }
        return INSTANCE;
    }

    private String getBaseUrl() {
        return QSDKHelper.getInstance().getConfigureModel().getGateway().length() == 0 ? BASE_URL : QSDKHelper.getInstance().getConfigureModel().getGateway();
    }

    private String getBaseVersion() {
        return QSDKHelper.getInstance().getConfigureModel().getVersion().length() == 0 ? BASE_VERSION : QSDKHelper.getInstance().getConfigureModel().getVersion();
    }

    private OkHttpClient getOkHttpClient() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(15000, TimeUnit.MILLISECONDS);
        builder.readTimeout(15000, TimeUnit.MILLISECONDS);
        builder.writeTimeout(15000, TimeUnit.MILLISECONDS);
        return builder.build();
    }

    private Call req(Activity context, boolean isPost, final String url, HashMap<String, Object> params, QResultCallback callback) {
        final String reqUrl = getBaseUrl() + getBaseVersion() + url;
        String tag = reqUrl + new Random().nextInt(10000);
        final QResultCallback resCallback = callback;
        if (params == null) {
            params = new HashMap<String, Object>();
        }

        params.put("app_id", QSDKHelper.getInstance().getConfigureModel().getGameId());
//        params.put("adid", QSDKHelper.getInstance().getConfigureModel().getAdid());
//        params.put("androidId", QSDKHelper.getInstance().getConfigureModel().getAndroidId());
        params.put("device_id", QSDKHelper.getInstance().getConfigureModel().getDeviceId());

        Request request = null;
        if (isPost) {
            request = new Request.Builder()
                    .url(reqUrl)
                    .tag(tag)
                    .cacheControl(CacheControl.FORCE_NETWORK)
                    .post(
                            RequestBody.create(
                                    MediaType.parse("application/json;"),
                                    new Gson().toJson(params))
                    )
                    .build();
        }else{
            String reqUrl2 = reqUrl + "?";
            for (String k : params.keySet()) {
                reqUrl2 += k + "=" + String.valueOf(params.get(k)) + "&";
            }
            request = new Request
                    .Builder()
                    .cacheControl(CacheControl.FORCE_NETWORK)
                    .url(reqUrl2)
                    .tag(tag)
                    .get()
                    .build();
        }

        final HashMap<String, Object> finalParams = params;
        Call call = getOkHttpClient().newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                try {
                    Log.e(TAG, "");
                    Log.e(TAG, "---------------start------------");
                    Log.e(TAG, "Api:" + call.request().url().toString());
                    Log.e(TAG, "param:" + finalParams.toString());
                    Log.e(TAG, e.getMessage());
                    Log.e(TAG, "---------------end------------");
                    Log.e(TAG, "");
                }catch (Exception ee){

                }
                if (context == null || (context != null && context.isFinishing())) return;
                sendFailResultCallback(-1, Language.System_Network_Error.toString(), resCallback);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String str = "";
                try {
                    str = response.body().string();
                    Log.e(TAG, "");
                    Log.e(TAG, "---------------start------------");
                    Log.e(TAG, "Api:" + response.request().url().toString());
                    Log.e(TAG, "param:" + finalParams.toString());
                    Log.e(TAG, str);
                    Log.e(TAG, "---------------end------------");
                    Log.e(TAG, "");
                }catch (Exception e){

                }
                if (!response.isSuccessful()) {
                    getInstance().sendFailResultCallback(response.code(), response.message(), resCallback);;
                    return;
                }
                if (context == null || (context != null && context.isFinishing())) return;

                try {
                    QCommonResultBaseBean r = new Gson().fromJson(str, resCallback.mType);
                    int code = r.getCode();
                    if (code == 0) {
                        sendSuccessResultCallback(r, resCallback);
                    } else {
                        SDKInfoModel sdkInfoModel = QSDKHelper.getInstance().getConfigureModel();
                        InitModel initModel = sdkInfoModel.getInitModel();
                        if (initModel.getI18n().containsKey(code + "")) {
                            sendFailResultCallback(code, fillStringByArgs(initModel.getI18n().get(code + "").get(sdkInfoModel.getCurrencyLang().toString()), r.getMsg()), resCallback);
                        }else {
                            sendFailResultCallback(code, Language.System_Error.toString(), resCallback);
                        }
                    }
                } catch (Exception e) {
                    sendFailResultCallback(500, e.getMessage(), resCallback);
                }
            }
        });
        return call;
    }

    public String fillStringByArgs(String str, String[] arr) {
        Matcher m = Pattern.compile("(%@)").matcher(str);//Matcher m = Pattern.compile("\\{(\\d)\\}").matcher(str);
        int curr = 0;
        while (m.find()) {
            if (curr >= arr.length) return str;
            str = str.replaceFirst(m.group(), arr[curr]);//str = str.replace(m.group(), arr[Integer.parseInt(m.group(1))]);
            curr++;
        }
        return str;
    }

    private void sendSuccessResultCallback(final Object object, final QResultCallback callback) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.onSuccess(object);
            }
        });
    }

    private void sendFailResultCallback(final int code, final String object, final QResultCallback callback) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.onError(code, object);
            }
        });
    }
}
